/**
 * @fileoverview implementation of factory for sensors defined in configuration
 *
 * @author Sebastian Brzuzek sebastian@brzuzek.pl
 */

goog.provide('uxperf.profiler.Profiler');

goog.require('goog.events.EventTarget');
goog.require('uxperf.Config');
goog.require('uxperf.FactoryBase');
goog.require('uxperf.FactoryBase.Autoinit');
goog.require('uxperf.Collector');
goog.require('uxperf.profiler.SensorBase');
goog.require('uxperf.profiler.SensorNavigation');
//goog.require('uxperf.profiler.SensorResource');
goog.require('uxperf.profiler.SensorAjax');
goog.require('uxperf.profiler.SensorBrowserEvent');
//goog.require('uxperf.profiler.SensorKey');

/**
 * mapping of target type names to classes
 * @type {Object}
 */
uxperf.profiler.SENSOR_CLASSES_MAP = {};
uxperf.profiler.SENSOR_CLASSES_MAP[uxperf.profiler.SensorNavigation.TYPE_NAME] = uxperf.profiler.SensorNavigation;
//uxperf.profiler.SENSOR_CLASSES_MAP[uxperf.profiler.SensorResource.TYPE_NAME] = uxperf.profiler.SensorResource;
uxperf.profiler.SENSOR_CLASSES_MAP[uxperf.profiler.SensorAjax.TYPE_NAME] = uxperf.profiler.SensorAjax;
uxperf.profiler.SENSOR_CLASSES_MAP[uxperf.profiler.SensorBrowserEvent.TYPE_NAME] = uxperf.profiler.SensorBrowserEvent;
//uxperf.profiler.SENSOR_CLASSES_MAP[uxperf.profiler.SensorKey.TYPE_NAME] = uxperf.profiler.SensorKey;

/**
 * Return instance of Profiler as defined in current configuration
 *
 * @param {Function=} opt_callback
 * @constructor
 * @extends {goog.events.EventTarget}
 * @implements {uxperf.FactoryBase.Autoinit}
 * @throws {Error}
 */
uxperf.profiler.Profiler = function(opt_callback) {
	goog.base(this);
	
	if (opt_callback) goog.events.listen(this, uxperf.FactoryBase.EVENT_TYPE_READY, opt_callback);
	
	/**
	 * profiler readiness (initialized) flag
	 * @type {boolean}
	 * @private
	 */
	this.ready_ = false;
	
	/**
	 * Array of active sensors
	 * 
	 * @type {Array.<uxperf.profiler.SensorBase>}
	 * @private
	 */
	this.sensors_ = [];

	/**
	 * Sensors count from configuration
	 * 
	 * @type {number}
	 */
	this.sensorsCount_ = 0;
	
	/**
	 * Ready sensors count
	 * 
	 * @type {number}
	 */
	this.sensorsReady_ = 0;
	
	/**
	 * Collector of data
	 * @type {uxperf.Collector}
	 * @private
	 */
	this.collector_ = uxperf.Collector.getInstance();

	//config default
	
	//autoinit
	if (uxperf.Config.get(uxperf.profiler.Profiler.CONFIG.AUTOINIT_KEY) !== false) {
    if (this.collector_.queue_.isReady()) this.init();
		goog.events.listenOnce(this.collector_.queue_, uxperf.FactoryBase.EVENT_TYPE_READY, this.init);
	}
};
goog.inherits(uxperf.profiler.Profiler, goog.events.EventTarget);

/**
 * singleton instance of Profiler
 * 
 * @type {uxperf.profiler.Profiler}
 */
uxperf.profiler.Profiler.instance_ = null;

/**
 * Return instance of Profiler as defined in current configuration
 * Singleton getter
 *
 * @param {Function=} opt_callback
 */
uxperf.profiler.Profiler.getInstance = function(opt_callback) {
  if (!uxperf.profiler.Profiler.instance_)
    uxperf.profiler.Profiler.instance_ = new uxperf.profiler.Profiler(opt_callback);
  return uxperf.profiler.Profiler.instance_;
};

/**
 * initialization of profiler
 * @return {uxperf.profiler.Profiler}
 */
uxperf.profiler.Profiler.prototype.init = function () {
	if (this.ready_) return this;

	if (!this.collector_.isReady()) {
		this.collector_.init(); //it is important to have queue available before we start any sensor
	}

	//prepare sensors
	this.sensorsCount_ = uxperf.Config.get(uxperf.profiler.SensorBase.CONFIG.KEY).length || 0;
	
	var profiler = this;
	for (var i=0; i < this.sensorsCount_; i++) {
		this.sensors_[i] = /** @type {uxperf.profiler.SensorBase} */ (uxperf.FactoryBase.getInstance(
			uxperf.profiler.SENSOR_CLASSES_MAP, //map
			/** @type {string} */ (uxperf.profiler.SensorBase.getParam(i, uxperf.profiler.SensorBase.CONFIG.TYPE_KEY)), //type
			/** @type {string} */ (uxperf.profiler.SensorBase.getParam(i, uxperf.profiler.SensorBase.CONFIG.AUTOINIT_KEY)), //initmode
			/** @type {number|null|undefined} */ (uxperf.profiler.SensorBase.getParam(i, uxperf.profiler.SensorBase.CONFIG.AUTOINIT_DELAY_KEY)), //delay
			false, //caseSensitive
			//callback
			function () {
				profiler.sensorsReady_++;
				if (profiler.sensorsReady_ >= profiler.sensorsCount_)
					//profiler.ready_ = true; //TODO:
					profiler.dispatchEvent(uxperf.profiler.Profiler.EVENT_TYPE_READY_ALL_SENSORS);
			},
			//var_args
			i
		));
	}
	//TODO: should we wait for all sensors to be ready?
	this.ready_ = true;
	this.dispatchEvent(uxperf.FactoryBase.EVENT_TYPE_READY);
	return this;
};

/**
 * @const event type for readiness of all sensors
 */
uxperf.profiler.Profiler.EVENT_TYPE_READY_ALL_SENSORS = 'ready_all_sensors';

/**
 * profiler configuration option keys
 * @enum {string}
 */
uxperf.profiler.Profiler.CONFIG = {
  AUTOINIT_KEY: 'profiler_autoinit'
};
